/**
 * Copyright (c) 2022 Presto Labs Pte. Ltd.
 * Author: Ju
 */

#pragma once

#include <boost/asio/io_service.hpp>
#include <boost/asio/connect.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/spawn.hpp>
#include <cstdint>
#include <memory>
#include <string>

namespace coin2::exchange::base::order {
using boost::asio::ip::tcp;

class TcpConnection : public std::enable_shared_from_this<TcpConnection> {
 public:
  class Callback {
   public:
    virtual ~Callback() = default;
    virtual void OnRawDataReceived(std::weak_ptr<TcpConnection> conn,
                                   char *buffer, uint32_t len) = 0;

    virtual void OnDataSent(uint32_t len){
      (void)len;
    };
  };

  explicit TcpConnection(boost::asio::io_context *ioc);
  ~TcpConnection();

  void Start();
  void Close();
  void SendMsg(std::string buffer);

  tcp::socket &Socket();

  // remote address
  std::string Ip();
  uint16_t Port();

  void RegisterCallback(Callback *callback);

 private:
  static const uint32_t MAX_SIZE = 4096;

 private:
  boost::asio::io_context *ioc_;
  boost::asio::io_service::strand strand_;
  tcp::socket socket_;
  Callback *callback_;

  std::vector<char> buffer_;
};

inline tcp::socket &TcpConnection::Socket() { return socket_; }

inline std::string TcpConnection::Ip() {
  return socket_.remote_endpoint().address().to_string();
}

inline uint16_t TcpConnection::Port() {
  return socket_.remote_endpoint().port();
}

inline void TcpConnection::RegisterCallback(Callback *callback) {
  callback_ = callback;
}

}  // namespace coin2::exchange::base::order
